﻿namespace Bildverarbeitung.CGFilter
{
    using System;
    using System.Drawing;
    using Bildverarbeitung;
    using System.Drawing.Imaging;

    /// <summary>
    /// 
    /// </summary>
    public class HeinzPatrikFilter : Bildverarbeitung.IFilter
    {
        /// <summary>
        /// Gets the summerized difference from average of all images.
        /// </summary>
        /// <param name="images">Given images.</param>
        /// <returns>The summerized difference.</returns>
        public Bitmap GetSummerizedDifferencefromAverage(Bitmap[] inputImages)
        {
            if (inputImages.Length < 1)
            {
                return null;
            }
            else
            {
                unsafe
                {
                    //position 0 in all arrays will be the result image 'durchschnittsbild'
                    Bitmap[] images = new Bitmap[inputImages.Length + 1];
                    byte*[] imgPointers = new byte*[inputImages.Length + 1];
                    BitmapData[] imgData = new BitmapData[inputImages.Length + 1];
                    //get pointers so all images
                    for (int i = 0; i <= inputImages.Length; i++)
                    {
                        if (i == 0)
                        {
                            // generate empty bitmap on first images array position
                            images[i] = new Bitmap(inputImages[i].Width, inputImages[i].Height, PixelFormat.Format24bppRgb);
                        }
                        else
                        {
                            images[i] = inputImages[i - 1];
                        }

                        imgData[i] = images[i].LockBits(
                                                        new Rectangle(new Point(0, 0), images[i].Size),
                                                        ImageLockMode.ReadWrite,
                                                        PixelFormat.Format24bppRgb);

                        imgPointers[i] = (byte*)imgData[i].Scan0.ToPointer();
                    }

                    //get padding for the images
                    int padding = imgData[0].Stride - (images[0].Width * 3);
                    int[] r, g, b;
                    //iterate thru all pixels and set the median from all source image pixels
                    for (int y = 0; y < images[0].Height; y++)
                    {
                        for (int x = 0; x < images[0].Width; x++)
                        {
                            r = new int[inputImages.Length];
                            g = new int[inputImages.Length];
                            b = new int[inputImages.Length];
                            for (int i = 1; i < images.Length; i++)
                            {
                                r[i - 1] = imgPointers[i][2]; // R
                                g[i - 1] = imgPointers[i][1]; // G
                                b[i - 1] = imgPointers[i][0]; // B      
                            }
                            //calculate the median and set to the current pixel
                            Array.Sort(r);
                            Array.Sort(g);
                            Array.Sort(b);
                            imgPointers[0][2] = (byte)r[r.Length / 2]; // R
                            imgPointers[0][1] = (byte)g[r.Length / 2]; // G
                            imgPointers[0][0] = (byte)b[r.Length / 2]; // B

                            //next pixel
                            for (int i = 0; i < images.Length; i++)
                            {
                                imgPointers[i] += 3;
                            }
                        }
                        //next line
                        for (int i = 0; i < images.Length; i++)
                        {
                            imgPointers[i] += padding;
                        }
                    }
                    //lock images again
                    for (int i = 0; i < images.Length; i++)
                    {
                        images[i].UnlockBits(imgData[i]);
                    }
                    //display result
                    return images[0];
                }
            }
        }

        /// <summary>
        /// Return the author´s name
        /// Please use NachnameVorname (without spaces).
        /// </summary>
        /// <returns>author´s name</returns>
        public String GetName()
        {
            return ("HeinzPatrik");
        }
    }
}
